Fix: zero result buffers in MatrixUtils to prevent neural network output corruption#31
Open
clubsnake wants to merge 1 commit intokeiwando:masterfrom
Open
Fix: zero result buffers in MatrixUtils to prevent neural network output corruption#31clubsnake wants to merge 1 commit intokeiwando:masterfrom
clubsnake wants to merge 1 commit intokeiwando:masterfrom
Conversation
MatrixProduct and MatrixProductTranspose accumulate into a result buffer using +=, but never zero it first. When callers pass a pre-allocated buffer (as FeedForwardNetwork.CalculateOutputs does with tempResults on every tick), values from previous forward passes accumulate indefinitely instead of being computed fresh. The bug is masked by sigmoid activation saturation — after a few ticks the accumulated values grow so large that sigmoid maps everything near 0 or 1 regardless. This effectively corrupts the network's ability to produce nuanced, input-dependent outputs and limits creatures to simple repetitive motions rather than adaptive behavior. Fix: zero each result element before the inner accumulation loop. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The three matrix multiplication functions in
MatrixUtils.cs(MatrixProduct× 2,MatrixProductTranspose) accumulate into a result buffer using+=but never zero it first. When a caller passes a pre-allocated buffer — asFeedForwardNetwork.CalculateOutputs()does withtempResultson every physics tick — values from previous forward passes accumulate indefinitely instead of being computed fresh.Root cause
tempResultsis allocated in the constructor and never cleared. Each call toMatrixProductTransposeadds the new dot-product results on top of whatever was left from the last tick.Why it's hard to notice
Sigmoid activation saturates quickly. After ~5-10 ticks of accumulation, every pre-activation value is so large (positive or negative) that
sigmoid(x)maps it to ≈0 or ≈1 regardless of the actual inputs. The network still "works" — it just outputs near-constant values that ignore sensory input, which is why creatures converge on simple repetitive motions (e.g., rhythmic flexing) rather than developing adaptive, input-responsive gaits.Observable impact
Fix
Zero each result element before the inner accumulation loop — one line per function:
This is a minimal, safe change. When
resultis freshly allocated (thenullpath), the zeroing is redundant but harmless. Whenresultis reused (the bug path), it's essential.Testing
mastersourceFeedForwardNetwork.CalculateOutputs()passes reusedtempResultsbuffersBug discovered and fix authored with assistance from Claude (Anthropic).